﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using Subfaculty.Helpers;
using Entities;
using RepositoriesInterfaces;
using Subfaculty.ViewModels;

namespace Subfaculty.Controllers
{
    public class LoadDistributionController : Controller
    {
        IDepartmentRepository DepartmentRepository;
        ILoadAtomRepository LoadAtomRepository;
        ITeacherRepository TeacherRepository;

        public LoadDistributionController(IDepartmentRepository DepartmentRepository, ILoadAtomRepository LoadAtomRepository, ITeacherRepository TeacherRepository)
        {
            this.DepartmentRepository = DepartmentRepository;
            this.LoadAtomRepository = LoadAtomRepository;
            this.TeacherRepository = TeacherRepository;
        }

        public ActionResult Index(int id)
        {
            int currentDepartmentId = GetCurrentDepartmentId(id);
            int currentTeacherId = GetCurrentCurrentTeacherId(currentDepartmentId);            

            IList<LoadAtom> distributionLoadList = LoadAtomRepository.GetDistributionLoad(currentDepartmentId, currentTeacherId);
            IList<LoadAtom> notDistributionLoadList = LoadAtomRepository.GetNotDistributionLoad(currentDepartmentId);
            
            LoadDistributionViewModel model = new LoadDistributionViewModel
                                                {
                                                    distributionLoad = distributionLoadList,
                                                    notDistributionLoad = notDistributionLoadList,
                                                    teachersList = TeacherRepository.GetByDepartmentId(currentDepartmentId),
                                                    currentTeacher = TeacherRepository.GetByID(currentTeacherId)
                                                };
            return View(model);
        }

        
        // --------------AJAX FUNCTIONS--------------

        // Обновление дерева распределенной нагрузки (id - преподаватель)
        public PartialViewResult ajaxUpdateDistrTree(int id)
        {
            AjaxUpdateDistrTreeViewModel model = new AjaxUpdateDistrTreeViewModel
                                                    {
                                                        distributionLoad = LoadAtomRepository.GetDistributionLoad(1, id),
                                                        teacher = TeacherRepository.GetByID(id)
                                                    };
            return PartialView(model);
        }

        // Обновление дерева нераспределенной нагрузки (id - кафедра)
        public PartialViewResult ajaxUpdateNotDistrTree(int id)
        {
            AjaxUpdateNotDistrTreeViewModel model = new AjaxUpdateNotDistrTreeViewModel { NotDistributionLoad = LoadAtomRepository.GetNotDistributionLoad(id)};
            return PartialView(model);
        }

        // Обновление дерева для разделения атомов (id - кафедра)
        public PartialViewResult ajaxUpdateDivideTree(int id)
        {
            AjaxUpdateNotDistrTreeViewModel model = new AjaxUpdateNotDistrTreeViewModel { NotDistributionLoad = LoadAtomRepository.GetNotDistributionLoad(id) };
            return PartialView(model);
        }

        // Назначение атома преподавателю
        public String ajaxDistributeAtom(int teacherId, int atomId)
        {
            Teacher teacher = TeacherRepository.GetByID(teacherId);
            teacher.AddAtom(LoadAtomRepository.GetByID(atomId));
            TeacherRepository.SaveOrUpdate(teacher);

            return "ok";
        }

        // Назначение группы атомов одного типа преподавателю
        public String ajaxDistributeLoadType(int teacherId, int disciplineId, String _loadType)
        {
            String loadType = translateLoadTypeFormEnglish(_loadType);
            Teacher teacher = TeacherRepository.GetByID(teacherId);
            IList<LoadAtom> atomList = LoadAtomRepository.GetByDisciplineAndType(teacher.Department.Id, disciplineId, loadType, null);
            
            foreach (LoadAtom atom in atomList)
            {
                teacher.AddAtom(atom);
                TeacherRepository.SaveOrUpdate(teacher);
            }

            return "ok";
        }

        // Назначение группы атомов одной дисциплины преподавателю
        public String ajaxDistributeLoadDiscipline(int teacherId, int disciplineId)
        {
            Teacher teacher = TeacherRepository.GetByID(teacherId);
            IList<LoadAtom> atomList = LoadAtomRepository.GetByDiscipline(teacher.Department.Id, disciplineId, null);

            foreach (LoadAtom atom in atomList)
            {
                teacher.AddAtom(atom);
                TeacherRepository.SaveOrUpdate(teacher);
            }

            return "ok";
        }

        // Удаление распределения атома
        public String ajaxDistributedAtomDelete(int teacherId, int atomId)
        {
            Teacher teacher = TeacherRepository.GetByID(teacherId);
            LoadAtom atom = LoadAtomRepository.GetByID(atomId);
            teacher.LoadAtoms.Remove(atom);
            atom.Teacher = null;
            TeacherRepository.SaveOrUpdate(teacher);
            LoadAtomRepository.SaveOrUpdate(atom);

            return "ok";
        }

        // Удаление распределения группы атомов по типу нагрузки
        public String ajaxDistributedLoadTypeDelete(int teacherId, int disciplineId, String _loadType)
        {
            String loadType = translateLoadTypeFormEnglish(_loadType);
            Teacher teacher = TeacherRepository.GetByID(teacherId);
            IList<LoadAtom> atomList = LoadAtomRepository.GetByDisciplineAndType(teacher.Department.Id, disciplineId, loadType, teacher);

            foreach (LoadAtom atom in atomList)
            {
                teacher.LoadAtoms.Remove(atom);
                atom.Teacher = null;
                TeacherRepository.SaveOrUpdate(teacher);
                LoadAtomRepository.SaveOrUpdate(atom);
            }

            return "ok";
        }

        // Удаление распределения группы атомов по дисциплине
        public String ajaxDistributedLoadByDisciplineDelete(int teacherId, int disciplineId)
        {            
            Teacher teacher = TeacherRepository.GetByID(teacherId);
            IList<LoadAtom> atomList = LoadAtomRepository.GetByDiscipline(teacher.Department.Id, disciplineId, teacher);

            foreach (LoadAtom atom in atomList)
            {
                teacher.LoadAtoms.Remove(atom);
                atom.Teacher = null;
                TeacherRepository.SaveOrUpdate(teacher);
                LoadAtomRepository.SaveOrUpdate(atom);
            }

            return "ok";
        }

        // Удаление распределения группы атомов по дисциплине
        public String ajaxDivideLoadAtoms(int firstAtomHours, int secondAtomHours, int atomId)
        {
            LoadAtom atom = LoadAtomRepository.GetByID(atomId);
            CreateLoadAtom(atom.LoadType, atom.GroupRelationType, atom.Allocation, atom.Groups, firstAtomHours);
            CreateLoadAtom(atom.LoadType, atom.GroupRelationType, atom.Allocation, atom.Groups, secondAtomHours);

            foreach(Group group in atom.Groups)
                group.LoadAtoms.Remove(atom);
            atom.Allocation.LoadAtoms.Remove(atom);

            LoadAtomRepository.Delete(atom);

            return "ok";
        }

 

        // --------------PRIVATE FUNCTIONS--------------

        private int GetCurrentDepartmentId(int id)
        {
            IList<Department> DepartmentsList = DepartmentRepository.GetAll();
            int curId = id;
            if ((id == 0) && (DepartmentsList.Count != 0))
            {
                curId = DepartmentsList[0].Id;
            }
            return curId;
        }

        private int GetCurrentCurrentTeacherId(int currentDepartmentId)
        {
            IList<Teacher> teachersList = TeacherRepository.GetByDepartmentId(currentDepartmentId);
            int currentTeacherId = 0;
            if (teachersList.Count > 0) currentTeacherId = teachersList.First().Id;

            return currentTeacherId;
        }

        private String translateLoadTypeFormEnglish(String englishType)
        {
            IDictionary<String, String> loadTypeDictionary = new Dictionary<String, String>();
            loadTypeDictionary.Add("Lectures", "Лекции");
            loadTypeDictionary.Add("Practices", "Практики");
            loadTypeDictionary.Add("Labs", "Лабораторные");

            return loadTypeDictionary[englishType];
        }


        // ВСЕ ФУНКЦИИ С СОЗДАНИЕМ АТОМОВ ВЫНЕСТИ В ОТДЕЛЬНЫЙ КЛАСС, Т.К. ДУБЛИРУЮТСЯ В ALLOCATION КОНТРОЛЛЕРЕ!!!!!!!!!!!!!!!!!

        // Генерирует атом нагрузки
        private void CreateLoadAtom(String LoadType, String typeSplitting, Allocation allocation, IList<Group> groups, int AtomHours)
        {
            if (typeSplitting == "oneGroup")
                GenerateLoadAtomToEachGroup(allocation, LoadType, groups, AtomHours);
            else if (typeSplitting == "allGroups")
                GenerateLoadAtomToAllGroup(allocation, LoadType, groups, AtomHours);
            else if (typeSplitting.StartsWith("halfGroup"))
                GenerateLoadAtomToHalfGroup(allocation, LoadType, groups, AtomHours);
        }

        // Сгенерировать атом для всех подгрупп
        private void GenerateLoadAtomToHalfGroup(Allocation allocation, string LoadType, IList<Group> groups, int atomHours)
        {
            LoadAtom atom;
            IList<Group> tempGroupList = new List<Group>();

            foreach (Group item in groups)
            {
                tempGroupList.Clear();
                tempGroupList.Add(item);
                atom = CreateNewAtom(LoadType, tempGroupList, allocation, "halfGroup" + "_1", atomHours);
                LoadAtomRepository.SaveOrUpdate(atom);
                allocation.LoadAtoms.Add(atom);
                atom = CreateNewAtom(LoadType, tempGroupList, allocation, "halfGroup" + "_2", atomHours);
                LoadAtomRepository.SaveOrUpdate(atom);
                allocation.LoadAtoms.Add(atom);
            }
        }

        // Сгенерировать атом для всех групп из списка
        private void GenerateLoadAtomToAllGroup(Allocation allocation, String LoadType, IList<Group> groups, int atomHours)
        {
            LoadAtom atom = CreateNewAtom(LoadType, groups, allocation, "allGroups", atomHours);
            LoadAtomRepository.SaveOrUpdate(atom);
            allocation.LoadAtoms.Add(atom);
        }

        // Сгенерировать атомы для каждой группы из списка в отдельности
        private void GenerateLoadAtomToEachGroup(Allocation allocation, String LoadType, IList<Group> groups, int atomHours)
        {
            LoadAtom atom;
            IList<Group> tempGroupList = new List<Group>();

            foreach (Group item in groups)
            {
                tempGroupList.Clear();
                tempGroupList.Add(item);
                atom = CreateNewAtom(LoadType, tempGroupList, allocation, "oneGroup", atomHours);
                LoadAtomRepository.SaveOrUpdate(atom);
                allocation.LoadAtoms.Add(atom);
            }
        }

        private LoadAtom CreateNewAtom(String loadType, IList<Group> groups, Allocation allocation, String GroupRelationType, int atomHours)
        {
            LoadAtom atom = new LoadAtom();

            atom.LoadType = loadType;
            atom.Teacher = null;
            atom.Allocation = allocation;
            atom.GroupRelationType = GroupRelationType;

            if (loadType == "Лекции")
                atom.Hours = atomHours;
            else if (loadType == "Практики")
                atom.Hours = atomHours;
            else if (loadType == "Лабораторные")
                atom.Hours = atomHours;
            LoadAtomRepository.Save(atom);
            foreach (Group item in groups)
                item.AddAtom(atom);

            return atom;
        }
    }
}
